#include "richterdatabase.h"
#include "exception.h"
#include "mysqlcommands.h"
#include <cstring>
#include <iostream>
#include <vector>
#include <sstream>
#include <cstdarg>

using namespace std;


RichterDatabase &RichterDatabase::instance()
{
    static RichterDatabase inst;
    return inst;
}

void RichterDatabase::connect(const char *server,
                              const char *user,
                              const char *password)
{
    m_connect = mysql_init(0);

    if (!m_connect) {
        // TODO: Exception
    }

    MYSQL * result = mysql_real_connect(m_connect, server, user, password, 0, 0,NULL,0);

    if (!result) {
        throw Exception(mysql_error(m_connect));
    } else {
        cout << "Kapcsolat kiepitve" << endl;
    }

    // check database
    if (checkDatabaseExists() == true) {
        cout << "Adatbazis letezik" << endl;
        // check tables
        if (mysql_select_db(m_connect, "richter") == 0) {
            cout << "Adatbazishoz csatlakoztam" << endl;
        } else {
            throw Exception(mysql_error(m_connect));
        }

    } else {
        cout << "Adatbazis nem letezik, letrehozom!" << endl;
        // create database
        query(CREATE_DATABASE);

        if (mysql_select_db(m_connect, "richter") == 0) {
            cout << "Adatbazishoz csatlakoztam" << endl;
        } else {
            throw Exception(mysql_error(m_connect));
        }

        // create tables

        //query(CREATE_MATERIAL_TABLE);
        //query(CREATE_MATERIAL_SPEC_META_TABLE);
    }
    fixTables();
}

RichterDatabase::~RichterDatabase()
{
    mysql_close (m_connect);

    mysql_library_end();
}

void RichterDatabase::addPlace(const char *name)
{
//INSERT INTO places (description) VALUES ("raktar");
    insertInto("places", 1, "description", name);
}

vector<Places> RichterDatabase::getPlaces()
{
    vector<Places> result;
    query("SELECT * FROM `places`;");

    MYSQL_RES *res_set;
    MYSQL_ROW row;

    res_set=mysql_store_result(m_connect);

    while (((row=mysql_fetch_row(res_set)) != 0))
    {
        Places newPlace;
        newPlace.id = atoi(row[0]);
        newPlace.description = row[1];
        result.push_back(newPlace);
    }

    mysql_free_result(res_set);


    return result;
}

void RichterDatabase::removePlace(int id)
{
    ostringstream os;
    os << "DELETE FROM `richter`.`places` WHERE `places`.`id` = " << id;
    query( os.str().c_str() );
}

RichterDatabase::RichterDatabase()
{
}

RichterDatabase::RichterDatabase(const RichterDatabase &eredeti)
{

}

bool RichterDatabase::checkDatabaseExists()
{
    MYSQL_RES *res_set;
    MYSQL_ROW row;

    mysql_query(m_connect, "SHOW DATABASES");
    res_set=mysql_store_result(m_connect);

    while (((row=mysql_fetch_row(res_set)) != 0))
    {
        if (strcmp(row[0], "richter") == 0) {
            mysql_free_result(res_set);
            return true;
        }
    }

    mysql_free_result(res_set);
    return false;

}

void RichterDatabase::query(const char *command) const
{
    int result = mysql_query(m_connect, command);
    if (result != 0) {
        throw Exception(mysql_error(m_connect));
    }
}

void RichterDatabase::fixTables()
{
    unsigned int counter = 0;
    vector< TableData > tables;
    tables.push_back( {"material", CREATE_MATERIAL_TABLE} );
    tables.push_back( {"material_spec_meta", CREATE_MATERIAL_SPEC_META_TABLE} );
    tables.push_back( {"state", CREATE_STATE_TABLE} );
    tables.push_back( {"places", CREATE_PLACES_TABLE} );
    tables.push_back( {"charge", CREATE_CHARGE_TABLE} );
    tables.push_back( {"material_spec", CREATE_MATERIAL_SPEC_TABLE} );
    tables.push_back( {"producing", CREATE_PRODUCING_TABLE} );
    tables.push_back( {"auth", CREATE_AUTH_TABLE} );
    tables.push_back( {"users", CREATE_USERS_TABLE} );
    tables.push_back( {"auth_data", CREATE_AUTH_DATA_TABLE} );

    vector< TableData >::iterator iter = tables.begin();
    vector< TableData >::iterator iterEnd = tables.end();
    for (; iter != iterEnd; iter++) {
        if ( tableExists(iter->m_name) == false ) {
            // ha nem letezik, akkor letrehozzuk
            cout << "A(z) " << iter->m_name << "tabla nem letezik, letrehozom" << endl;
            query(iter->m_createCommand);
        } else {
            counter++;
        }
        //cout << iter->m_createCommand << endl;
    }

    cout << counter << " / " << tables.size() << " tabla letezett" << endl;
}

bool RichterDatabase::tableExists(const char *name) const
{
    MYSQL_RES *res_set;
    MYSQL_ROW row;

    query("SHOW TABLES;");
    res_set=mysql_store_result(m_connect);

    while (((row=mysql_fetch_row(res_set)) != 0))
    {
        if (strcmp(row[0], name) == 0) {
            mysql_free_result(res_set);
            return true;
        }
    }

    mysql_free_result(res_set);
    return false;

}

void RichterDatabase::insertInto(char *tableName, unsigned int count, ...)
{
    va_list arguments;
    va_start(arguments, count);
    ostringstream str;

    str << "INSERT INTO " << tableName << " (";
    unsigned int index;
    for (index = 0; index < count; index++) {
        str << va_arg(arguments, const char *);
        if (index < count - 1) {
            str << ", ";
        }
    }
    str << ") VALUES (";
    for (index = 0; index < count; index++) {
        str << "\"" << va_arg(arguments, const char *) << "\"";
        if (index < count - 1) {
            str << ", ";
        }
    }
    str << ");";
    cout << str.str();
    query( str.str().c_str() );
}

